package com.tutucms.service.admin.common;

import com.tutucms.common.exception.TokenInvalidException;
import com.tutucms.repo.entity.User;
import com.tutucms.service.auth.UserContextCache;
import com.tutucms.service.cache.CacheService;
import com.tutucms.service.common.SessionHolder;
import com.tutucms.service.auth.TokenValidator;
import com.tutucms.service.model.consts.Const;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 * Created by wangxudong on 2020/03/10.
 *
 * @version: 1.0
 * @modified :
 */
@Order(1113)
@Slf4j
@Aspect
@Component
public class TokenAuthAspect {

    @Autowired
    private UserContextCache userContextCache;

    @Value("${app.token.timeout:4320}")
    private Long tokenTimeOut;

    @Pointcut("@within(com.tutucms.service.auth.TokenValidator) || @annotation(com.tutucms.service.auth.TokenValidator)")
    private void tokenAuthCheck() {
    }

    @Around("tokenAuthCheck()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        log.debug("validate token.");
        Signature signature = pjp.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method targetMethod = methodSignature.getMethod();
        TokenValidator tokenValidator = targetMethod.getAnnotation(TokenValidator.class);

        // 方法上的注解优先级大于类
        if (tokenValidator == null) {
            tokenValidator = pjp.getTarget().getClass().getAnnotation(TokenValidator.class);
            if (tokenValidator != null) {
                redisCheckToken(tokenValidator.value());
            }
        } else {
            redisCheckToken(tokenValidator.value());
        }

        return pjp.proceed();
    }

    private void redisCheckToken(boolean isCheck) {
        HttpServletRequest request = SessionHolder.getRequest();
        String token = request.getHeader("Authorization");
        Long userId = userContextCache.get(Const.USER_TOKEN_PREFIX + token, Long.class, tokenTimeOut);
        if (StringUtils.isEmpty(token) || userId == null) {
            if (isCheck) {
                throw new TokenInvalidException("token 无效");
            }
        } else {
            User userInfo = userContextCache.get(Const.USER_KEY_PREFIX + userId, User.class, tokenTimeOut);

            if (userInfo == null) {
                if (isCheck) {
                    throw new TokenInvalidException("请重新登录");
                }
            }
            if (userInfo != null && userInfo.getDisabled() != null && userInfo.getDisabled()) {

                throw new TokenInvalidException("账号被封禁");
            }


            request.setAttribute(Const.CURRENT_ATTRIBUTE_KEY, userInfo);
        }
    }
}
